package com.ben.upload.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ben.upload.FileConfig;
import com.ben.upload.data.BaseResult;
import com.ben.upload.data.FileResult;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Component
@Controller
public class FileController {

    private final Logger logger = LoggerFactory.getLogger(FileController.class);

    private final FileConfig serverConfig;

    public FileController(FileConfig serverConfig) {
        this.serverConfig = serverConfig;
    }

    @RequestMapping("file/del")
    @ResponseBody
    public BaseResult delete(@RequestParam("path") String path) {
        try {
            if (null == path || path.isEmpty()) {
                return new BaseResult(-1, "path is null or empty");
            }
            String uploadPath = serverConfig.getUploadPath();
            String fileName = uploadPath + path.replace(serverConfig.getUrlPath(), "");
            File file = new File(fileName);
            if (file.exists()) {
                file.delete();
            } else {
                return new BaseResult(1, "file does not exist");
            }
            return new BaseResult(0, "delete success");
        } catch (Exception e) {
            return new BaseResult(1, "delete err :" + e.getMessage());
        }
    }

    @RequestMapping("file/dels")
    @ResponseBody
    public BaseResult deletes(@RequestParam("paths") String files) {
        try {
            if (null == files || files.isEmpty()) {
                return new BaseResult(-1, "path is null or empty");
            }
            String uploadPath = serverConfig.getUploadPath();
            String[] paths = files.split(",");
            for (int i = paths.length - 1; i >= 0; i--) {
                String path = paths[i];
                if (StringUtils.isEmpty(path)) {
                    continue;
                }
                String fileName = uploadPath + path.replace(serverConfig.getUrlPath(), "");
                File file = new File(fileName);
                if (file.exists()) {
                    file.delete();
                }
            }
            return new BaseResult(0, "delete success");
        } catch (Exception e) {
            return new BaseResult(1, "delete err :" + e.getMessage());
        }
    }

    @RequestMapping("file/clear")
    @ResponseBody
    public BaseResult clear(@RequestParam("paths") String paths) {
        try {
            if (StringUtils.isEmpty(paths)) {
                return new BaseResult(-1, "rarameter null");
            }
            String uploadPath = serverConfig.getUploadPath();
            String urlPath = serverConfig.getUrlPath();
            String[] arrayString = paths.split(",");
            ArrayList<String> pathList = new ArrayList<>();
            for (String str : arrayString) {
                if (StringUtils.isEmpty(str)) {
                    continue;
                }
                pathList.add(str.replace(urlPath, ""));
            }
            File file = new File(uploadPath);
            traverseFile(file, childFile -> {
                String fileName = childFile.getAbsolutePath();
                String localFile = fileName.replace(uploadPath, "");
                if (!pathList.contains(localFile)) {
                    childFile.delete();
                }
            });
            deleteEmptyDirectory(file);
            return new BaseResult(0, "clear success");
        } catch (Exception e) {
            return new BaseResult(1, "clear err :" + e.getMessage());
        }
    }


    @RequestMapping("/file/upload")
    @ResponseBody
    public FileResult upload(@RequestParam("file") MultipartFile file, String address) {
        try {
            String fileName = file.getOriginalFilename();
            if (fileName == null) {
                return new FileResult(-1, "originalFilename is null");
            }
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            String falgPath = suffix.replace(".", "") + "/";
            String path = serverConfig.getUploadPath() + falgPath;
            String uuid = UUID.randomUUID().toString();
            File saveFile = new File(path);
            if (!saveFile.exists()) {
                saveFile.mkdirs();
            }
            File outFile = new File(path + uuid + suffix);
            file.transferTo(outFile);
            String md5 = DigestUtils.md5DigestAsHex(Files.newInputStream(outFile.toPath()));
            String filePath = serverConfig.getUrlPath() + falgPath + uuid + suffix;
            String myAddress = StringUtils.isEmpty(address) ? serverConfig.getUrl() : address;
            return new FileResult(myAddress + filePath,
                    filePath,
                    uuid + suffix,
                    fileName,
                    md5
            );
        } catch (Exception e) {
            logger.error("upload:err" + e.fillInStackTrace());
            return new FileResult(-1, e.toString());
        }
    }

    @RequestMapping("/file/uploads")
    @ResponseBody
    public Object uploads(@RequestParam("files") List<MultipartFile> files, String address) {
        try {
            List<FileResult> retList = new ArrayList<>();
            for (MultipartFile file : files) {
                String fileName = file.getOriginalFilename();
                if (fileName == null) {
                    return new BaseResult(-1, "originalFilename is null");
                }
                String suffix = fileName.substring(fileName.lastIndexOf("."));
                String falgPath = suffix.replace(".", "") + "/";
                String path = serverConfig.getUploadPath() + falgPath;
                String uuid = UUID.randomUUID().toString();
                File saveFile = new File(path);
                if (!saveFile.exists()) {
                    saveFile.mkdirs();
                }
                File outFile = new File(path + uuid + suffix);
                file.transferTo(outFile);
                String md5 = DigestUtils.md5DigestAsHex(Files.newInputStream(outFile.toPath()));
                String filePath = serverConfig.getUrlPath() + falgPath + uuid + suffix;
                String myAddress = StringUtils.isEmpty(address) ? serverConfig.getUrl() : address;
                retList.add(new FileResult(myAddress + filePath,
                        filePath,
                        uuid + suffix,
                        fileName,
                        md5
                ));
            }
            return retList;
        } catch (Exception e) {
            logger.error("upload:err" + e.fillInStackTrace());
            return new BaseResult(-1, e.toString());
        }
    }

    /**
     * 遍历所有文件
     */
    private void traverseFile(File rootDirectory, RunFileTask runnable) throws IOException {
        File[] files = rootDirectory.listFiles();
        if (files == null) {
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                traverseFile(file, runnable);
                continue;
            }
            runnable.run(file);
        }
    }

    /**
     * 删除某文件目录下的所有空白文件夹
     */
    public static void deleteEmptyDirectory(File file) {
        //1、如果本来文件就为null,那么就返回
        if (file == null) {
            return;
        }
        if (!file.exists()) {
            return;
        }
        File[] files = file.listFiles();
        if (files == null || files.length == 0) {
            file.delete();
            return;
        }
        for (File f : files) {
            if (!f.isDirectory()) {
                continue;
            }
            deleteEmptyDirectory(f);
        }
        if (file.listFiles().length == 0) {
            file.delete();
        }
    }

    interface RunFileTask {
        void run(File childFile);
    }
}
